package singleton;

//1.饿汉式
class Connection1 {
    private static final Connection1 connection = new Connection1();

    private Connection1() {}        // 私有构造方法，防止外部实例化

    public static Connection1 getConnection() {
        return connection;
    }
}

//2.懒汉式
class Connection2 {
    public static Connection2 connection;

    private Connection2() {}

    public static Connection2 getConnection() {
        if (connection == null) {            // 第一次调用时创建实例
            connection = new Connection2();
        }
        return connection;
    }
}

//3.线程安全的懒汉式
class Connection3 {
    public static Connection3 connection;

    private Connection3() {
    }

    public static synchronized Connection3 getConnection() {
        if (connection == null) {
            connection = new Connection3();
        }
        return connection;
    }
}

//4.双重锁检查
//线程A，B并发执行，同时通过第一次检查
//线程A上锁后，线程B等待，待线程A释放锁后，线程将B持有锁，第二次检查防止创建多个实例
class Connection4 {

    private Connection4() {}

    private static volatile Connection4 connection;    //防止指令重排，确保对象初始化后再赋值

    public static Connection4 getConnection() {
        if (connection == null) {           // 第一次检查，避免不必要的同步
            synchronized (Connection4.class) {
                if (connection == null) {   // 第二次检查，防止多个线程同时进入，创建多个实例
                    connection = new Connection4();
                }
            }
        }
        return connection;
    }
}

//5.静态内部类
//依赖于JVM 的类加载机制，JVM 会保证一个类只被加载一次，从而保证线程安全
class Connection5 {

    private Connection5() {
    }

    private static class Connection5Holder {
        private static final Connection5 connection = new Connection5();
    }

    public static Connection5 getConnection() {
        return Connection5Holder.connection;
    }
}


//6.枚举单例
enum Connection6 {
    CONNECTION;

    public static Connection6 getConnection() {
        return CONNECTION;
    }
}

public class ConnectionTest {
    public static void main(String[] args) {
        Connection1 connection1 = Connection1.getConnection();
        System.out.println(connection1);

        Connection2 connection2 = Connection2.getConnection();
        System.out.println(connection2);

        Connection3 connection3 = Connection3.getConnection();
        System.out.println(connection3);

        Connection4 connection4 = Connection4.getConnection();
        System.out.println(connection4);

        Connection5 connection5 = Connection5.getConnection();
        System.out.println(connection5);

        Connection6 connection6 = Connection6.getConnection();
        System.out.println(connection6);
    }
}